﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DotSpatial.Data;

namespace GeostatisticalTool.Classes
{
    public  class CalculateErrorsCrossValidation
    {
        private IFeatureSet data;
        private CheckDataInput check;
        public CalculateErrorsCrossValidation(IFeatureSet data,CheckDataInput check)
        { 
          this.data=data;
          this.check = check;
        }

        public List<double[]> UpdatePredictedTable(IInterpolator predic, int trend, string transform)
        {
            //"Measured","Trans","Trend","Predicted","Error","StdError"
        List<double[]> lists= new List<double[]>();
        List<double> predictedValues = new List<double>();
        List<double> observedValues = new List<double>();
        List<double> error = new List<double>();
        List<double> stdError = new List<double>();

        #region Checkvalues
        foreach (Feature fea1 in data.Features)
        {
            double[] value = predic.Interpolate(fea1.Coordinates[0].X, fea1.Coordinates[0].Y, fea1.Coordinates[0].Z,false);
            if (!value[0].Equals(double.NaN) && !value[1].Equals(double.NaN))
            {
                if (trend != 0)
                {

                    if (transform == "None")
                    {
                        //used= (real or trans)  - trend;
                        //(real or trans)= (used or pred) + trend;

                        fea1.DataRow["Predicted"] = value[0] + Convert.ToDouble(fea1.DataRow["Trend"]);
                        fea1.DataRow["Error"] = Convert.ToDouble(fea1.DataRow["Predicted"]) - Convert.ToDouble(fea1.DataRow["Measured"]);
                        fea1.DataRow["StdError"] = value[1];

                    }
                    else
                    {

                        fea1.DataRow["Predicted"] = check.TransformInverse(transform, (value[0] + Convert.ToDouble(fea1.DataRow["Trend"])));
                        fea1.DataRow["Error"] = check.TransformInverse(transform, Convert.ToDouble(fea1.DataRow["Predicted"]) - Convert.ToDouble(fea1.DataRow["Measured"]));
                        fea1.DataRow["StdError"] = check.TransformInverse(transform, value[1]);

                    }

                }
                else
                {

                    if (transform == "None")
                    {
                        //used= (real or trans)  - trend;
                        //(real or trans)= (used or pred) + trend;
                        fea1.DataRow["Predicted"] = value[0]; ;
                        fea1.DataRow["Error"] = Convert.ToDouble(fea1.DataRow["Predicted"]) - Convert.ToDouble(fea1.DataRow["Used"]);
                        fea1.DataRow["StdError"] = value[1];
                    }
                    else
                    {
                        fea1.DataRow["Predicted"] = check.TransformInverse(transform, (value[0]));
                        fea1.DataRow["Error"] = check.TransformInverse(transform, Convert.ToDouble(fea1.DataRow["Predicted"]) - Convert.ToDouble(fea1.DataRow["Used"]));
                        fea1.DataRow["StdError"] = check.TransformInverse(transform, value[1]);
                    }

                }

                predictedValues.Add(Convert.ToDouble(fea1.DataRow["Predicted"]));
                observedValues.Add(Convert.ToDouble(fea1.DataRow["Measured"]));
                error.Add(Convert.ToDouble(fea1.DataRow["Error"]));
                stdError.Add(Convert.ToDouble(fea1.DataRow["StdError"]));
            }
        }
        #endregion

        lists.Add(observedValues.ToArray());
        lists.Add(predictedValues.ToArray());
        lists.Add(error.ToArray());
        lists.Add(stdError.ToArray());
        
            return lists;

        }

        public List<double[]> UpdatePredictedTableDeterministics(IInterpolator predic, int trend, string transform)
        {
            //"Measured","Trans","Trend","Predicted","Error","StdError"
            List<double[]> lists = new List<double[]>();
            List<double> predictedValues = new List<double>();
            List<double> observedValues = new List<double>();
            List<double> error = new List<double>();

            #region Checkvalues
            foreach (Feature fea1 in data.Features)
            {
                double[] value = predic.Interpolate(fea1.Coordinates[0].X, fea1.Coordinates[0].Y,fea1.Coordinates[0].Z, false);
                if (value[0].Equals(double.NaN))
                    break;
                fea1.DataRow["Predicted"] = value[0] ;
                fea1.DataRow["Error"] = Convert.ToDouble(fea1.DataRow["Predicted"]) - Convert.ToDouble(fea1.DataRow["Measured"]);
                predictedValues.Add(Convert.ToDouble(fea1.DataRow["Predicted"]));
                observedValues.Add(Convert.ToDouble(fea1.DataRow["Measured"]));
                error.Add(Convert.ToDouble(fea1.DataRow["Error"]));
               
            }
            #endregion

            lists.Add(observedValues.ToArray());
            lists.Add(predictedValues.ToArray());
            lists.Add(error.ToArray());
            return lists;
        }


        public double[] CrossValidationRegression(String ValueColumnX, String ValueColumnY)
        {
            double[] output = new double[3];
            Stat sumX = new Stat(false);
            Stat sumY = new Stat(false);
            Stat sumX2 = new Stat(false);
            Stat sumY2 = new Stat(false);
            Stat sumXY = new Stat(false);

            int numberUsed =0;
            foreach (Feature fea1 in data.Features)
            {
                double z;
                double zIn; 
                try
                {
                     z = Convert.ToDouble(fea1.DataRow[ValueColumnX]);
                     zIn = Convert.ToDouble(fea1.DataRow[ValueColumnY]);
                     sumX += new Stat(z);
                     sumY += new Stat(zIn);
                     sumX2 += new Stat(z * z);
                     sumY2 += new Stat(zIn * zIn);
                     sumXY += new Stat(z * zIn);
                     numberUsed++;
                }
                catch
                {
                   
                }
                //if (z.Equals(double.NaN) || zIn.Equals(double.NaN))
                //    break;

 

              }
              output[0] = ((numberUsed * sumXY.value) - (sumX.value * sumY.value)) / (numberUsed * sumX2.value - (sumX.value * sumX.value)); // B slope
              output[1] = ((sumY.value / numberUsed) - output[0] * (sumX.value / numberUsed)); // intercept
              output[2] = ((numberUsed * sumXY.value) - (sumX.value * sumY.value))
                              / Math.Sqrt((numberUsed * sumX2.value - sumX.value * sumX.value) * (numberUsed * sumY2.value - sumY.value * sumY.value)); // correlation coefficient
         
            return output;
        }


    }
}
